import jsonServer from 'json-server';
import meow from 'meow';
import os from 'os';
import cors from 'cors'


// 获取内网 IP 地址
function getLocalIP() {
  const interfaces = os.networkInterfaces(); // 获取所有网络接口
  let localIP = ''; // 初始化内网 IP 变量

  Object.keys(interfaces).forEach((ifname) => { // 遍历所有网络接口
    interfaces[ifname].forEach((iface) => { // 遍历每个接口的地址信息
      if (iface.family === 'IPv4' && !iface.internal) { // 检查地址是否为 IPv4 且不是回环地址
        localIP = iface.address; // 设置内网 IP 地址
      }
    });
  });

  return localIP; // 返回内网 IP 地址
}
const localIP = getLocalIP(); // 调用函数获取内网 IP 地址

// 使用 meow 解析命令行参数
const cli = meow(`
  使用方式：
    $ npm run serve -- --port 5432 --apiPath api/v1 --allowedOrigins "http://localhost:5173,http://localhost:3000" --auth "your-token"

  参数：
    --port, -p            监听的端口号，默认值：5432
    --apiPath, -a         API 路径前缀，不能用 '/' 作为前缀，默认值： api/v1
    --allowedOrigins, -o  允许的跨域来源，逗号分隔，默认值：无
    --auth, -u            认证 token，默认值：无
`, {
  importMeta: import.meta,
  flags: {
    port: {
      type: 'number',
      shortFlag: 'p',
      default: 5432,
    },
    apiPath: {
      type: 'string',
      shortFlag: 'a',
      default: 'api/v1',
    },
    allowedOrigins: {
      type: 'string',
      shortFlag: 'o',
      default: '*',
    },
    auth: {
      type: 'string',
      shortFlag: 'u',
      default: '',
    },
  },
});

// 获取命令行参数
const { port, apiPath, allowedOrigins, auth } = cli.flags;

// 不能传入 '/' 开头的 api，是因为在 windows 的 git bash 下，会把 '/' 认定为当前 git 的安装目录，然后被安装目录也拼接到 api 上
// 其他环境是否也会拼接未知
const normalizeApiPath = '/' + apiPath


// 创建服务器
const server = jsonServer.create(); // 创建 json-server 实例
const router = jsonServer.router('./db.json'); // 使用 db.json 文件作为数据源


// 跨域相关
// 如果命令行的 '-o' 值是下面 3 个，那么是允许任意源的
if (!allowedOrigins || allowedOrigins === 'true' || allowedOrigins === '*') {
  // 默认允许跨域，没有缓存、开启日志。
  server.use(jsonServer.defaults());
} else if (allowedOrigins === 'false') {
  // 如果命令行传入的源为 false，则不允许跨域
  server.use(jsonServer.defaults({ noCors: true }));
} else {
  // 除了上面两种情况，认定传递的源是符合 origin 规则的字符串
  const allowedOriginsList = allowedOrigins.split(','); // 转为数组

  const corsOptions = {
    origin: function (origin, callback) {
      if (allowedOriginsList.indexOf(origin) !== -1 || !origin) { // 如果来源在白名单中或者没有来源（例如本地测试）
        callback(null, true); // 允许请求
      } else {
        callback(new Error('Not allowed by CORS')); // 拒绝请求
      }
    }
  };
  const corsMiddleware = cors(corsOptions)
  server.use(corsMiddleware);
}


// 简单的认证中间件
const authMiddleware = (req, res, next) => {
  // 如果没有配置认证 Token，则跳过认证
  if (!auth || typeof auth !== 'string' || auth.trim() === '') {
    next();
    return;
  }

  // 验证 Authorization 头
  const token = req.headers.authorization;
  if (token !== `Bearer ${auth}`) {
    res.status(401).json({ error: '未授权访问' });
    return;
  }

  next(); // 验证通过，继续处理请求
};

server.use(authMiddleware); // 应用认证中间件


server.use(jsonServer.bodyParser); // 支持 JSON 数据的处理

server.use(normalizeApiPath, router); // 由于传入的 api 没有 '/' 开头，这里需要拼接 '/'，

// 全局错误处理中间件
server.use((err, req, res, next) => {
  console.error('Global error handler:', err.stack); // 打印错误堆栈
  res.status(500).send('服务器内部错误'); // 发送 500 错误响应
});

// 尝试启动服务器
function startServer(port) {
  server.listen(port, () => {
    console.log('服务已启动...')

    console.log(`允许的跨域源：${allowedOrigins}`);

    // 输出认证信息
    if (auth && auth.trim()) {
      console.log(`启用认证，认证 token 是：Bearer ${auth}`);
    } else {
      console.log('未启用 Bearer 认证');
    }

    // 拼接正确的本地 URL，确保路径正确拼接
    const localURL = `http://localhost:${port}${normalizeApiPath}`;
    console.log(`本  地 URL 是：${localURL}`); // 输出本地地址

    // 确保局域网地址也正确拼接
    if (localIP) {
      const lanURL = `http://${localIP}:${port}${normalizeApiPath}`;
      console.log(`局域网 URL 是：${lanURL}`); // 输出局域网地址
    }
  }).on('error', (err) => {
    if (err.code === 'EADDRINUSE') {
      console.log(`端口 ${port} 被占用，尝试下一个端口启动...`);
      startServer(port + 1); // 递增端口号并重新尝试启动
    } else {
      console.error('服务启动失败，', err);
    }
  });
}
startServer(port); // 开始启动服务器
